home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1_3 / sys / amiga / splitter / loader.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-20  |  10.2 KB  |  460 lines

  1. /*     SCCS Id: @(#)loader.c 3.1    93/01/08
  2. /*    Copyright (c) Kenneth Lorber, Bethesda, Maryland 1992, 1993 */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * Amiga split binary runtime system
  7.  */
  8.  
  9. /*#define LDEBUG         /* turn on debugging I/O */
  10. #define SDEBUG        /* static primary array allocation */
  11. /*#define NOCLEAN        /* turn off ovl$memchain code */
  12. /*#define NOSPLIT        /* debug: load an unsplit binary(run ONCE!)*/
  13. #define MULTI            /* real file reading code */
  14. /*#define PARANOID        /* check for refs off end that might be OK */
  15. #define CACHE            /* deal with cache flushing */
  16.  
  17. unsigned long xx;
  18. long *yy;
  19.  
  20. #include "split.h"
  21.  
  22. #ifdef SPLIT
  23.  
  24. #include <stdio.h>        /* for spanic - should change */
  25. #include <exec/types.h>
  26. #include <exec/memory.h>
  27. #include <libraries/dosextens.h>
  28. #include <proto/dos.h>
  29. #include <proto/exec.h>
  30. #include <dos.h>            /* NOT libraries/dos.h! */
  31. #include <setjmp.h>
  32.  
  33. jmp_buf jbuf;
  34.  
  35. #include "amiout.h"
  36.  
  37. #include "multi.h"
  38.  
  39. #define F_LOAD 0
  40. #define F_RELOAD 1
  41.  
  42. #define HT(x)    ((x) & ~MEM_OBJ_EXTEND)
  43.  
  44. void *ovl$AllocMem(unsigned int);
  45. void spanic(char *);            /* think about this!!!! */
  46. void exit(int);
  47.  
  48. #ifdef SDEBUG
  49. unsigned long *ovl$hunktable[500];    /* 229 as of 2/3/93 */
  50. #else
  51. unsigned long *(*ovl$hunktable)[];
  52. int ovl$hunktablesize;
  53. #endif
  54.  
  55. #ifndef NOCLEAN
  56. BPTR ovl$memchain=0;
  57. #endif
  58. BPTR ovlfile=0;
  59. BPTR fh;
  60. ULONG database;
  61.  
  62. BPTR s_LoadSeg(char *);
  63. void s_UnLoadSeg(void);
  64. BPTR load_code(int,char *);
  65. void load_data(int,char *);
  66. unsigned long *load_hunk(BPTR,int,ULONG *);
  67.  
  68. #ifdef MULTI
  69. union multiopts mo;
  70.     /* dump these after testing */
  71. #define Read MultiRead
  72. #define Close MultiClose
  73. #endif
  74.  
  75. BPTR
  76. s_LoadSeg(dir)
  77.     char *dir;
  78.     {
  79.     static BPTR base;
  80.     static char never=1;
  81.  
  82.     if( setjmp( jbuf ) != 0 )
  83.         return( NULL );
  84.     if(never){
  85. #ifdef LDEBUG
  86.         fprintf(stderr,"s_LoadSeg waiting\n");
  87.         Delay(100);
  88.         fprintf(stderr,"going\n");
  89. #endif
  90.         base=load_code(F_LOAD,dir);
  91. #ifndef NOSPLIT
  92.         load_data(F_LOAD,dir);
  93.         never=0;
  94. #endif
  95.     }else{
  96.         load_data(F_RELOAD,dir);
  97.     }
  98. #ifdef LDEBUG
  99.     fprintf(stderr,"loadseg done! (waiting)\n");
  100.     getchar();
  101. #endif
  102. #ifdef CACHE
  103.     {
  104.     struct Library *eb=OpenLibrary("exec.library",36);
  105.     if(eb){
  106.         CacheClearU();
  107.         CloseLibrary(eb);
  108.     } else {
  109.         /* force a context switch and hope for the best */
  110.         Delay(1);
  111.     }
  112.     }
  113. #endif
  114.     return(base);
  115. }
  116.  
  117. BPTR
  118. load_code(dummy,dir)
  119.     int dummy;    /* always F_LOAD */
  120.     char *dir;    /* direction file */
  121. {
  122.     ULONG x;
  123.     ULONG *xp;
  124.     ULONG c,hc;
  125.     ULONG r;
  126. #ifdef MULTI
  127.     mo.r.mor_tag='C';
  128.     fh=MultiOpen(dir,MODE_OLDFILE,&mo);
  129. #else
  130.     fh=Open("s_NetHack.c00",MODE_OLDFILE);
  131. #endif
  132.     if(fh==0){
  133.         fprintf(stderr,"open failed %d\n",IoErr());
  134.         spanic("missing code file");
  135.     }
  136.     Read(fh,&x,4);    /* HUNK_HEADER */
  137.     Read(fh,&x,4);    /* 0 */
  138.     Read(fh,&hc,4);    /* table size */
  139. #ifdef LDEBUG
  140.     fprintf(stderr,"hunk count=%d\n",hc);
  141. #endif
  142. #ifndef SDEBUG
  143.     ovl$hunktable= (long*(*)[])ovl$AllocMem(hc*4);
  144.     ovl$hunktablesize=hc*4;
  145. #endif
  146. #ifdef LDEBUG
  147.     fprintf(stderr,"table at %08x\n",ovl$hunktable);
  148. #endif
  149.     Read(fh,&x,4);    /* F==0 */
  150.     Read(fh,&x,4);    /* L==size-1 */
  151.     for(c=0;c<hc;c++){
  152.         Read(fh,&x,4);
  153. #ifdef SDEBUG
  154.         xx=ovl$hunktable[c]=ovl$AllocMem(x*4);
  155. #else
  156.         xx=(*ovl$hunktable)[c]=ovl$AllocMem(x*4);
  157. #endif
  158. #ifdef LDEBUG
  159.         fprintf(stderr,"t[%d]=%08x, len=%08x\n",c,xx,((long*)xx)[-2]);
  160. #endif
  161.     }
  162. #ifdef LDEBUG
  163.     fprintf(stderr,"TABLE LOADED\n");Delay(50);
  164. #endif
  165.     for(c=0,xp=(unsigned long*)1;xp;c++){
  166. #ifdef LDEBUG
  167. # ifdef SDEBUG
  168.         yy=ovl$hunktable[c];
  169. # else
  170.         yy=(*ovl$hunktable)[c];
  171. # endif
  172.         fprintf(stderr,"loading hunk %d@%08x len=%08x\n",c,yy,yy[-2]);
  173. #endif
  174. #ifdef SDEBUG
  175.         xp=load_hunk(fh,dummy,ovl$hunktable[c]);
  176. #else
  177.         xp=load_hunk(fh,dummy,(*ovl$hunktable)[c]);
  178. #endif
  179.     }
  180.     database=c-1;    /* first hunk for use for data on each load */
  181.     Close(fh);
  182. #ifdef LDEBUG
  183. # ifdef SDEBUG
  184.     fprintf(stderr,"retval=%08x\n",ovl$hunktable[0]);
  185. # else
  186.     fprintf(stderr,"retval=%08x\n",(*ovl$hunktable)[0]);
  187. # endif
  188. #endif
  189. #ifdef SDEBUG
  190.     r= (unsigned long) ovl$hunktable[0];        /* BPTR to seglist */
  191. #else
  192.     r= (unsigned long) (*ovl$hunktable)[0];    /* BPTR to seglist */
  193. #endif
  194.     return (BPTR)(r>>2)-1;
  195. }
  196.  
  197. void
  198. load_data(fl,dir)
  199.     int fl;
  200.     char *dir;
  201. {
  202.     int c;
  203.     unsigned long *x;
  204. #ifdef MULTI
  205.     mo.r.mor_tag='D';
  206.     fh=MultiOpen(dir,MODE_OLDFILE,&mo);
  207. #else
  208.     fh=Open("s_NetHack.d00",MODE_OLDFILE);
  209. #endif
  210.             /* doing it this way we don't need the hunk count */
  211.     for(c=database,x=(unsigned long*)1;x;c++){
  212. #ifdef SDEBUG
  213.         x=load_hunk(fh,fl,ovl$hunktable[c]);
  214. #else
  215.         x=load_hunk(fh,fl,(*ovl$hunktable)[c]);
  216. #endif
  217.     }
  218. #ifdef LDEBUG
  219.     fprintf(stderr,"end of load_data (waiting)\n");
  220.     getchar();
  221. #endif
  222.     Close(fh);
  223. }
  224.  
  225. unsigned long *
  226. load_hunk(ovlfile,fl,lbase)
  227.     BPTR ovlfile;        /* AmigaDOS file handle */
  228.     int fl;
  229.     ULONG *lbase;
  230. {
  231.     unsigned long data[2];
  232.     unsigned long *where;
  233.     unsigned long reloc_type;
  234.     static int lbufsize=680;    /* max xref in one hunk 347 2/3/93 */
  235.     static unsigned long *lbuf=0;    /* load buffer */
  236.     unsigned long *lbp;
  237.     unsigned short *lbps;
  238.  
  239.     if(!lbuf)lbuf=malloc(lbufsize*4);
  240.     if(!lbuf)spanic("Can't allocate lbuf");
  241. #ifdef LDEBUG
  242. # ifndef MULTI
  243.     {
  244.     int pos=Seek(ovlfile,0,0);
  245.     fprintf(stderr,"load_hunk (fpos=%08x) @%08x len=%08x(%08x)\n",pos,
  246.         lbase,lbase[-2],lbase[-2]/4);
  247.     }
  248. # endif
  249. #endif
  250.     if(0==Read(ovlfile,data,sizeof(data))){
  251. #ifdef LDEBUG
  252.         fprintf(stderr,"getchar EOF\n");
  253.         getchar();
  254. #endif
  255.         return(0);    /* EOF */
  256.     }
  257. #ifdef LDEBUG
  258.     fprintf(stderr,"read type=%08x len=%08x\n",data[0],data[1]<<2);
  259. #endif
  260.     if( HT(data[0])!=HUNK_CODE &&
  261.         HT(data[0])!=HUNK_DATA &&
  262.         HT(data[0])!=HUNK_BSS){
  263.         fprintf(stderr,"bad data=%08x\n",data[0]);
  264.         spanic("ovlfile cookie botch");
  265.     }
  266.     where=lbase;
  267. #if 0
  268.                 /* clear memory if:
  269.                  * 1. not the first time (MEMF_CLEAR'd already)
  270.                  * 2. data or bss (just in case)
  271.                  * This is just a sanity check since these are
  272.                  * the only hunks we should be seeing on reload.
  273.                  */
  274.     if(fl==F_RELOAD && (HT(data[0])==HUNK_DATA || HT(data[0])==HUNK_BSS)
  275. #endif
  276.     {
  277.         ULONG *p=where;        /* clear memory block */
  278.         ULONG c=(where[-2]/4)-1;    /* (len includes ptr) */
  279. #if 0            /* don't ship enabled - Gigamem returns 0 */
  280.         if(!TypeOfMem(p))spanic("clearing bogus memory");
  281. #endif
  282.         while(c--)*p++=0;    /* not memset - use longs for speed */
  283.     }
  284.  
  285.     if(HT(data[0])==HUNK_DATA || HT(data[0])==HUNK_CODE){
  286.         xx=Read(ovlfile,where,data[1]*4);    /* load the block */
  287.         if(xx!=data[1]*4){
  288.             fprintf(stderr,"Read(%08x,%08x)->%08x\n",where,
  289.               data[1]*4,xx);
  290.             spanic("out of data");
  291.         }
  292.     } else {
  293. #ifdef LDEBUG
  294.         fprintf(stderr,"BSS - no load\n");
  295. #endif
  296.     }
  297.             /* link/relocate as needed */
  298.     xx=Read(ovlfile,&reloc_type,sizeof(reloc_type));
  299.     if(xx!=sizeof(reloc_type))spanic("lost reloc_type");
  300.     while(reloc_type!=HUNK_END){
  301.         unsigned long reloc_count;
  302.         unsigned long reloc_count2;
  303.         unsigned long *base;
  304.         unsigned long reloc_offset;
  305.         unsigned long reloc_shift;
  306.         int hnum;
  307.         if(reloc_type==HUNK_END)continue;    /* and quit */
  308.         if(reloc_type!=HUNK_RELOC32 && reloc_type!=HUNK_RELOC32s){
  309.             fprintf(stderr,"bad data %08x\n",reloc_type);
  310.             spanic("ovlfile reloc cookie botch");
  311.         }
  312.         reloc_shift=(reloc_type==HUNK_RELOC32)?2:1;
  313.         xx=Read(ovlfile,&reloc_count,sizeof(reloc_count));
  314.         if(xx!=sizeof(reloc_count))spanic("lost reloc_count");
  315.  
  316.         reloc_count2=reloc_count;
  317.         while(reloc_count){     /* fix indent */
  318.             if((reloc_count<<reloc_shift) >= (lbufsize*4)){
  319.                 free(lbuf);
  320.                 lbufsize=10+reloc_count;
  321.                 lbuf=malloc(lbufsize*4);
  322.                 if(!lbuf)spanic("Can't realloc lbuf");
  323.             }
  324.             xx=Read(ovlfile,lbuf,((1+reloc_count)<<reloc_shift));
  325.             if(xx!=((1+reloc_count)<<reloc_shift))
  326.                 spanic("can't fill lbuf");
  327.             lbp= &lbuf[1];        /* 0 is reloc_hunk */
  328.             lbps= ((unsigned short *)lbuf)+1;
  329.             hnum=(reloc_shift==2)? lbp[-1]: lbps[-1];
  330. #ifdef SDEBUG
  331.             base=ovl$hunktable[hnum];
  332. #else
  333.             base=(*ovl$hunktable)[hnum];
  334. #endif
  335. #ifdef LDEBUG
  336.             fprintf(stderr,"reloc #%d: hunk #%d@%08x\n",
  337.               reloc_count,hnum,base);
  338. #endif
  339.             while(reloc_count--){
  340.                 if(reloc_shift==2){
  341.                     reloc_offset= *lbp++;
  342.                 } else {
  343.                     reloc_offset= *lbps++;
  344.                 }
  345.                 if(reloc_offset<0 || reloc_offset>where[-2]){
  346.                     fprintf(stderr,"where[-2]==%08x\n",
  347.                       where[-2]);
  348.                     spanic("offset out of hunk");
  349.                 }
  350.                 {
  351.                 ULONG *p=(ULONG*)(((ULONG)where)+reloc_offset);
  352. #ifdef PARANOID
  353. /* NB - nasty violation of signed/unsigned here */
  354.                 {
  355.                 if(*p > base[-2])
  356.                   fprintf(stderr,
  357.                   "WARNING: offset points outside block\n");
  358.                 }
  359. #endif
  360. #ifdef LDEBUG
  361.                 fprintf(stderr,
  362.                   "reloc_offset=%08x where=%08x p=%08x\n",
  363.                   reloc_offset,where,p);
  364.                 fprintf(stderr," current *p=%08x\n",*p);
  365. #endif
  366.                 (*p)+=(unsigned long)base;
  367. #ifdef LDEBUG
  368.                 fprintf(stderr," new *p=%08x\n",*p);
  369. #endif
  370.                 }
  371.             }
  372.             if( reloc_shift == 1 && (reloc_count2 & 1) == 0){ /* longword align */
  373.                 short x;
  374.                 Read(ovlfile,&x,sizeof(x));
  375.             }
  376.             xx=Read(ovlfile,&reloc_count,sizeof(reloc_count));
  377.             if(xx!=sizeof(reloc_count))spanic("lost reloc_count2");
  378.             reloc_count2=reloc_count;
  379.         }
  380.         xx=Read(ovlfile,&reloc_type,sizeof(reloc_type));
  381.         if(xx!=sizeof(reloc_count))spanic("lost reloc_type2");
  382.     }
  383. /* BUG -
  384.  * lbuf never freed
  385.  */
  386.     return(where);            /* return execute start point */
  387. }
  388.  
  389. /*
  390.     -2    len (bytes)
  391.     -1    next block
  392.      0    data
  393.  */
  394. void *
  395. ovl$AllocMem(len)
  396.     unsigned int len;
  397.     {
  398.     unsigned long *adr;
  399.     ULONG length=(len&0x0fffffff);
  400.                 /* Always clear the memory.  On reload of
  401.                  * bss or data we have to do it manually */
  402.     adr=AllocMem(length+8,(6&(len>>29))|MEMF_CLEAR);
  403.     {
  404.         int type=6&(len>>29);
  405.         if(    type!=MEMF_CHIP &&
  406.             type!=MEMF_FAST &&
  407.             type!=MEMF_PUBLIC &&
  408.             type != 0
  409.         ){
  410.             printf("%08x %08x* ",len,type);
  411.             spanic("bad memory type");
  412.         }
  413.     }
  414.     if(!adr)spanic("allocation failure");
  415.     adr[0]=length;
  416. #ifndef NOCLEAN
  417.     adr[1]=(unsigned long)ovl$memchain;    /* list for freeing at end */
  418.     ovl$memchain=((long)adr>>2)+1;    /* BPTR to next ptr */
  419. # ifdef LDEBUG
  420.     fprintf(stderr,"Alloc: adr[0]=%08x adr[1]=%08x\n",adr[0],adr[1]);
  421. # endif
  422. #endif
  423.     return adr+2;
  424. }
  425.  
  426. void
  427. s_UnLoadSeg()
  428. {
  429. #ifndef NOCLEAN
  430.     BPTR p,p1;
  431.  
  432. # ifdef LDEBUG
  433.     fprintf(stderr,"starting Free loop: ovlmemchain=%x\n",ovl$memchain);
  434. # endif
  435.     for(p=ovl$memchain;p;p=p1){
  436.         p1=*(BPTR *)BADDR(p);
  437. # ifdef LDEBUG
  438.         fprintf(stderr,"Free(%x,%x)\n",BADDR(p-1),
  439.           (*(long *)BADDR(p-1))+8);
  440. # endif
  441.         FreeMem(BADDR(p-1),(*(long *)BADDR(p-1))+8);
  442.     }
  443. #endif
  444. #ifndef SDEBUG
  445.     FreeMem(ovl$hunktable,ovl$hunktablesize);
  446. #endif
  447.     return;
  448. }
  449.  
  450. /* this needs to be improved and integrated with wb.c */
  451. void
  452. spanic(s)
  453.     char *s;
  454. {
  455.     fprintf(stderr,"s_LoadSeg failed: %s\n",s);
  456.     s_UnLoadSeg();
  457.     longjmp( jbuf, -1 );
  458. }
  459. #endif /* SPLIT */
  460.